package com.mc.fastkit.utils

import com.mc.fastkit.constant.TimeMillis
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.GregorianCalendar
import java.util.Locale

/**
 * DateUtils
 * @author MasterChan
 * @date 2021-12-01 17:06
 */
object DateUtils {
    const val YMD_HMS = "yyyy-MM-dd HH:mm:ss"

    /**
     * 获取当前的日期
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return 以[date2String]格式化的当前日期
     */
    fun now(pattern: String = YMD_HMS): String {
        return date2String(Date(), pattern)
    }

    /**
     * 判断这个日期是否是今天
     * @param date Date
     * @return Boolean
     */
    fun isToday(date: Date): Boolean {
        return isToday(date.time)
    }

    /**
     * 判断这个日期是否是今天
     * @param millis Long
     * @return Boolean
     */
    fun isToday(millis: Long): Boolean {
        val minMillis = getDateStartMillis()
        return millis >= minMillis && millis < minMillis + TimeMillis.DAY
    }

    /**
     * 将Date转为字符串日期
     * @param date 需要格式化的日期
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return [pattern]格式的日期
     */
    fun date2String(date: Date, pattern: String = YMD_HMS): String {
        return SimpleDateFormat(pattern, Locale.getDefault()).format(date)
    }

    /**
     * 将时间戳转为字符串日期
     * @param millis 时间戳
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return [pattern]格式的日期
     */
    fun date2String(millis: Long, pattern: String = YMD_HMS): String {
        return date2String(Date(millis), pattern)
    }

    /**
     * 将字符串日期转为Date
     * @param source 日期
     * @param pattern 日期的格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return Date? 如果[date2String]与[source]格式对应错误，解析失败，返回null
     */
    fun string2Date(source: String, pattern: String = YMD_HMS): Date {
        return SimpleDateFormat(pattern, Locale.getDefault()).parse(source)!!
    }

    /**
     * 将时间戳转为日期
     * @param millis Long
     * @return Date
     */
    fun millis2Date(millis: Long): Date {
        return Date(millis)
    }

    /**
     * String格式的日期转为时间戳
     * @param source String格式的日期
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return Long
     */
    fun string2Millis(source: String, pattern: String = YMD_HMS): Long {
        return string2Date(source, pattern).time
    }

    /**
     * 时间戳转为String格式的日期
     * @param millis 时间戳
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return String
     */
    fun millis2String(millis: Long, pattern: String = YMD_HMS): String {
        return date2String(Date(millis), pattern)
    }

    /**
     * 计算两个日期相差的天数，如果[date2]>[date1]，返回正数，否则返回负数
     * @param date1 Date
     * @param date2 Date
     * @return Long
     */
    fun dayDiff(date1: Date, date2: Date): Long {
        return (date2.time - date1.time) / TimeMillis.DAY
    }

    /**
     * 计算两个日期相差的年数，如果[date2]>[date1]，返回正数，否则返回负数
     * @param date1 Date
     * @param date2 Date
     * @return Int
     */
    fun yearDiff(date1: Date, date2: Date): Int {
        return getYear(date2) - getYear(date1)
    }

    /**
     * 获取日期的年
     * @param date Date
     * @return Int
     */
    fun getYear(date: Date = Date()): Int {
        val calendar = Calendar.getInstance()
        calendar.time = date
        return calendar[Calendar.YEAR]
    }

    /**
     * 获取日期的月
     * @param date Date
     * @return Int
     */
    fun getMonth(date: Date = Date()): Int {
        val calendar = Calendar.getInstance()
        calendar.time = date
        return calendar[Calendar.MONTH] + 1
    }

    /**
     * 获取日期为月的第几天
     * @param date Date
     * @return Int
     */
    fun dayOfMonth(date: Date = Date()): Int {
        val calendar = Calendar.getInstance()
        calendar.time = date
        return calendar[Calendar.DATE]
    }

    /**
     * 获取日期是星期几
     * @param date Date
     * @return Int
     */
    fun dayOfWeek(date: Date = Date()): Int {
        val calendar = Calendar.getInstance()
        calendar.time = date
        return calendar[Calendar.DAY_OF_WEEK]
    }

    /**
     * 获取距离目标日期[day]天前的日期
     * @param date Date
     * @param day Int
     * @return Date
     */
    fun getDateBefore(date: Date, day: Int): Date {
        val cal = Calendar.getInstance()
        cal.timeInMillis = getDateEndMillis(date)
        cal.add(Calendar.DAY_OF_YEAR, -day)
        return cal.time
    }

    /**
     * 获取距离目标日期[day]天后的日期
     * @param date Date
     * @param day Int
     * @return Date
     */
    fun getAfterDate(date: Date, day: Int): Date {
        val cal = Calendar.getInstance()
        cal.timeInMillis = getDateEndMillis(date)
        cal.add(Calendar.DAY_OF_YEAR, day)
        return cal.time
    }

    /**
     * 日期转为周，例如：周一
     * @param source String格式的日期
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return String
     */
    fun getSimpleWeek(source: String, pattern: String = YMD_HMS): String {
        return getSimpleWeek(string2Date(source, pattern))
    }

    /**
     * 日期转为周，例如：周一
     * @param millis 时间戳
     * @return String
     */
    fun getSimpleWeek(millis: Long): String {
        return getSimpleWeek(Date(millis))
    }

    /**
     * 日期转为周，例如：周一
     * @param date 日期
     * @return String
     */
    fun getSimpleWeek(date: Date): String {
        return SimpleDateFormat("E", Locale.getDefault()).format(date)
    }

    /**
     * 日期转为星期，例如：星期一
     * @param source String格式的日期
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return String
     */
    fun getFullWeek(source: String, pattern: String = YMD_HMS): String {
        return getFullWeek(string2Date(source, pattern))
    }

    /**
     * 日期转为星期，例如：星期一
     * @param millis 时间戳
     * @return String
     */
    fun getFullWeek(millis: Long): String {
        return getFullWeek(Date(millis))
    }

    /**
     * 日期转为星期，例如：星期一
     * @param date 日期
     * @return String
     */
    fun getFullWeek(date: Date): String {
        return SimpleDateFormat("EEEE", Locale.getDefault()).format(date)
    }

    /**
     * 判断是否是AM
     * @param millis 时间戳
     * @return Boolean
     */
    fun isAm(millis: Long): Boolean {
        return isAm(millis2Date(millis))
    }

    /**
     * 判断是否是AM
     * @param source String格式的日期
     * @param pattern 日期格式，默认为 yyyy-MM-dd HH:mm:ss
     * @return Boolean
     */
    fun isAm(source: String, pattern: String = YMD_HMS): Boolean {
        return isAm(string2Date(source, pattern))
    }

    /**
     * 判断是否是AM
     * @param date 日期
     * @return Boolean
     */
    fun isAm(date: Date = Date()): Boolean {
        val calendar = Calendar.getInstance()
        calendar.time = date
        return calendar.get(GregorianCalendar.AM_PM) == 0
    }

    /**
     * 判断是否是闰年；公历年份是4的倍数，且不是100的倍数，为普通闰年。
     * 公历年份是整百数，且必须是400的倍数才是世纪闰年
     * @param date Date
     * @return Boolean
     */
    fun isLeapYear(date: Date): Boolean {
        val cal = Calendar.getInstance()
        cal.time = date
        val year = cal[Calendar.YEAR]
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
    }

    /**
     * 获取一天开始时的时间戳
     * @param date 默认为当天
     * @return Long
     */
    fun getDateStartMillis(date: Date = Date()): Long {
        val cal = Calendar.getInstance()
        cal.time = date
        cal[Calendar.HOUR_OF_DAY] = 0
        cal[Calendar.MINUTE] = 0
        cal[Calendar.SECOND] = 0
        cal[Calendar.MILLISECOND] = 0
        return cal.timeInMillis
    }

    /**
     * 获取一天结束时的时间戳
     * * @param date 默认为当天
     * @return Long
     */
    fun getDateEndMillis(date: Date = Date()): Long {
        val cal = Calendar.getInstance()
        cal.time = date
        cal[Calendar.HOUR_OF_DAY] = 23
        cal[Calendar.MINUTE] = 59
        cal[Calendar.SECOND] = 59
        cal[Calendar.MILLISECOND] = 999
        return cal.timeInMillis
    }

    /**
     * 判断是否是同一年
     * @param mills1 Long
     * @param mills2 Long
     * @return Boolean
     */
    fun isSameYear(mills1: Long, mills2: Long): Boolean {
        return isSameYear(Date(mills1), Date(mills2))
    }

    /**
     * 判断是否是同一年
     * @param date1 Date
     * @param date2 Date
     * @return Boolean
     */
    fun isSameYear(date1: Date, date2: Date): Boolean {
        val calendar1 = Calendar.getInstance()
        calendar1.time = date1
        val calendar2 = Calendar.getInstance()
        calendar2.time = date2
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
    }

    /**
     * 判断是否是同一天
     * @param date1 Date
     * @param date2 Date
     * @return Boolean
     */
    fun isSameDay(date1: Date, date2: Date): Boolean {
        val calendar1 = Calendar.getInstance()
        calendar1.time = date1
        val calendar2 = Calendar.getInstance()
        calendar2.time = date2
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)
               && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH)
               && calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH)
    }
}